const Route = require('koa-router')
const Goods = require('../../models/goods')
const Evaluation = require('../../models/evaluation')
const koaJwt = require('koa-jwt')
const secretKey = require('../../config/keys').secretKey
const mongoose = require('mongoose')

const router = new Route()

/**
 * @method GET
 * @route /goods/getGoods
 * @param pageSize pageNum query
 * @description 用户获取商品列表 不需要验证jwt
 */
router.get('/getGoods', async ctx => {
  console.log(ctx.query)
  const pageNum = parseInt(ctx.query.pageNum) || 1 // 获取查询的页码
  const pageSize = parseInt(ctx.query.pageSize) || 4 // 获取查询的条数
  const query = ctx.query.query || '' // 获取模糊查询
  const total = await Goods.count() // 获取表总记录数
  const pageCount = Math.ceil(total / pageSize)
  let list = []
  // 这里先判断一次是否还有更多 如果有再进行查询 优化性能?
  let hasMore = pageCount >= pageNum // 当前页数大于等于这次请求的页面 就表示还有 如果小于表示没有
  if (hasMore) { // 如果还有就进行请求
    // mongodb中进行模糊查询就在find里面添加参数就是了  $regex 表示正则匹配  使用 // 也可以 但是这里query是变量名所以不能使用/query/  不然就是匹配包含'query'
    // find({zhTitle:{ $regex: query }}) 就表示zhTitle字段中有query这个变量的字符串的结果
    // 还有几个操作符  参考地址:https://blog.csdn.net/yaomingyang/article/details/75103480
    // !官方文档:https://docs.mongodb.com/manual/reference/operator/query/nor/
    // *$or find({$or:[]}) or就是或的意思 传入一个数组,里面包含一个或多个查询条件 比如$or: [{ zhPrice: 2999 }, { enPrice: { $lt: 450 } }] 就查询zhPrice为2999的或者enPrice字段小于450的
    // *$in find({quantity:{$in:[20,50]}}) 表示查询quantity字段等于20或者等于50的值
    // *$and find({$and:[{price:{$ne:1.99}},{price:{$exists:true}}]}) $and表示且 这里表示查询price字段不等于1.99,而且price字段存在的结果
    // *$and有隐式执行 比如 find({price:{$ne:1.99,$exists:true}}) 与上面是一样的 或者 find({count:1,num:2}) 表示匹配count=1而且num=2的结果
    // *$not 表示非 比如find( { price: { $not: { $gt: 1.99 } } } ) 表示匹配price字段大于等于1.99或者price不存在的结果
    // *注意 $not操作符不支持$regex正则表达式操作，但是可以使用//表示正则表达式
    // *$nor 这个操作符相当于是$not 与 $or 的结合 find( { $nor: [ { price: 1.99 }, { qty: { $lt: 20 } }, { sale: true } ] }
    // *表示匹配price不等于1.99,或qty大于等于20,或sale不为true的情况  如果price,qty,sale不存在也是包括的
    list = await Goods.find({
      $or: [
        { zhTitle: { $regex: query } },
        { enTitle: { $regex: query } },
        { zhDescription: { $regex: query } },
        { enDescription: { $regex: query } }
      ]
    }).
      // !进行分页搜索的主要就在这里 Model.find().skip(条数*(页码-1)).limit(条数)
      // skip表示跳过  limit表示限制
      skip(pageSize * (pageNum - 1)).
      limit(pageSize)
    hasMore = pageCount > pageNum ? true : false // 总页数大于当前请求的页数就还有
    ctx.status = 200
    ctx.body = { pageCount, total, pageNum, pageSize, query, hasMore, list }
  } else { // 如果没有就不进行请求
    ctx.status = 200
    ctx.body = { pageCount, total, pageNum, pageSize, query, hasMore, list }
  }
})

/**
 * @method GET
 * @route /goods/detail
 * @param gid
 * @description 获取点击的商品详情 需要传入商品id 不需要验证token
 */
router.get('/detail', async ctx => {
  const { gid } = ctx.query
  // !注意 这里实可以这样的await返回一个promise然后再then 这样可以便于处理错误 而且如果不想进行赋值 也可以这样
  // await Goods.findOne({ _id: gid }).then(res => {
  //   console.log(res)
  //   ctx.status = 200
  //   ctx.body = res
  // }).catch(err => {
  //   console.log(err)
  //   ctx.status = 500
  //   ctx.body = { msg: 'not found', name: 'goods' }
  // })

  // 因为商品详情中有评价 所以需要进行联表查询
  // 使用 aggregate 聚合管道  有以下几个管道操作符 还有其他的 这里并没有列举完
  // !$project 增加,删除,重命名字段  比如 order.aggregate([{ $project:{ order_id:1 }]) 那么会查询order的所有条目
  // !但是输出值会输出条目的order_id字段(还有默认的_id)  还可以对该字段重命名
  // !比如将order_id命名为oid 命名的操作为order.aggregate([{ $project:{ "oid":"$order_id" }])
  // !$match 条件匹配,只有满足条件的文档才能进入下一阶段
  // !比如 order.aggregate([{$project:{ order_id:1}, { $match:{ price:{ $lt:90 } } }])
  // !就会在上面的基础上筛选出price字段小于90的结果
  // *$limit 限制结果的数量
  // *$skip 跳过文档的的数量
  // *$sort 条件排序
  // *$group 条件组合结果  分组也挺重要的 可以自己试一下
  // !$lookup 可以引入其他集合的数据 也就是关联查询的重点!
  await Goods.aggregate([
    // aggregate这里面匹配_id不能直接使用字符串 需要先转换为ObjectId mongoose.Types.ObjectId(gid) 这样转换
    { $match: { '_id': mongoose.Types.ObjectId(gid) } },
    { // 这里查询出来放在了 evaluations 数组里 但是我一直找不到怎样才能继续筛选这个数组  比如说 查询的结果很多 但是我只需要5条 还可以优化性能
      // 但是一直找不到 但是可以换一种方法 那就是不去关联查询 直接分两次查询 一次查询goods  一次查询evaluations
      // 我这里数据不多就不更改了
      $lookup: { // 关联查询   一个$lookup表示与一个表关联 如果想与多个表关联的话  可以添加多个$lookup
        from: 'evaluations',  // 与那个表进行关联
        localField: '_id', // 与Goods哪个字段进行关联
        foreignField: 'gid', // 与evaluations表哪个字段进行关联
        as: 'evaluations' // 查询出来的结果放到哪个字段中
        // 上面是关联查询两个有联系的表 如果向关联查询两个没有联系的表 可以使用pipeline字段 传入一个数组
        // 比如pipeline:[{$match:{year:2018}}]
      }
    }
  ]).then(res => {
    console.log(res)
    ctx.status = 200
    ctx.body = res
  }).catch(err => {
    console.log(err)
    ctx.status = 500
    ctx.body = err
  })
})

/**
 * @method POST
 * @route /goods/addGoods
 * @data zhTitle enTitle zhPrice enPrice img zhDescription enDescription inventory
 * @description 添加商品 需要验证token
 */
router.post('/addGoods', koaJwt({ secret: secretKey }), async ctx => {
  const { body } = ctx.request
  const newGoods = new Goods({
    ...body
  })
  await newGoods.save().then(res => {
    console.log(res, '创建成功')
    ctx.status = 200
    ctx.body = { msg: '创建成功' }
  }).catch(err => {
    console.log(err, '创建失败')
    ctx.status = 500
    ctx.body = { msg: '创建成功' }
  })

})

/*
* @method POST
* @route /goods/addEvaluation
* @data  gid star content
* @description 对商品添加评价
* */
router.post('/addEvaluation', koaJwt({ secret: secretKey }), async ctx => {
  const { id, name } = ctx.state.user
  const username = `${name[0]}<span>***</span>${name.slice(-1)}`
  // 注意 这里star 传过来是个字符串但是我没有进行格式转换依然存储成功了 mongoose进行存储是会自动进行简单的格式转换
  const { gid, star, content } = ctx.request.body
  await new Evaluation({
    uid: id, username, gid, star, content
  }).save().then(res => {
    console.log(res)
    ctx.status = 200
    ctx.body = res
  }).catch(err => {
    console.log(err)
    ctx.status = 500
    ctx.body = err
  })

})

module.exports = router.routes()
